Update ComfyUIdownloads.yml

This commit is contained in:
Dariusz L
2026-07-25 01:20:16 +02:00
parent 582f56179a
commit cd5e8fcac2
+250 -126
View File
@@ -1,4 +1,14 @@
name: Model Resolver Top Downloads Badge
# Reusable workflow
#
# Project metadata is read from pyproject.toml and the Comfy Registry API.
# No project-specific repository variables need to be configured manually.
# The workflow creates and maintains this internal repository variable automatically:
# COMFY_DOWNLOADS_GIST_ID
#
# Required repository secret:
# SECRET_TOKEN GitHub token with Gist and repository Actions variables write access
name: ComfyUI Top Downloads Badge
on:
schedule:
@@ -8,6 +18,12 @@ on:
permissions:
contents: write
env:
COMFY_DOWNLOADS_GIST_ID: ${{ vars.COMFY_DOWNLOADS_GIST_ID }}
BADGE_DOC: badges/DOWNLOADS.md
DATA_FILE: comfyui_downloads.json
GH_TOKEN: ${{ secrets.SECRET_TOKEN }}
jobs:
build:
runs-on: ubuntu-latest
@@ -15,39 +31,67 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: gh login
run: echo "${{ secrets.SECRET_TOKEN }}" | gh auth login --with-token
- name: Read project metadata and validate authentication
id: project
run: |
if [ -z "$GH_TOKEN" ]; then
echo "::error title=Missing SECRET_TOKEN::Add a GitHub token with Gist and repository Actions variables write access."
exit 1
fi
- name: Query Model Resolver API and find top download
gh auth status
python - <<'PY' >> "$GITHUB_OUTPUT"
from pathlib import Path
import tomllib
path = Path("pyproject.toml")
if not path.is_file():
raise SystemExit("pyproject.toml was not found")
with path.open("rb") as file:
config = tomllib.load(file)
node_id = str(config.get("project", {}).get("name", "")).strip()
if not node_id:
raise SystemExit("[project].name is missing in pyproject.toml")
print(f"node_id={node_id}")
PY
- name: Query Comfy Registry API and find top download
env:
COMFY_NODE_ID: ${{ steps.project.outputs.node_id }}
run: |
max_downloads=0
found_valid_data=false
top_node_json="{}"
node_id="Comfyui-Model-Resolver"
for i in {1..3}; do
echo "Fetching data for attempt $i..."
response_file="registry_response_$i.json"
if ! curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors \
-H "Accept: application/json" \
"https://api.comfy.org/nodes/${node_id}" > tmp_$i.json; then
"https://api.comfy.org/nodes/${COMFY_NODE_ID}" > "$response_file"; then
echo "Error: request failed for attempt $i"
rm -f tmp_$i.json
rm -f "$response_file"
continue
fi
if [ ! -s tmp_$i.json ] || ! jq empty tmp_$i.json 2>/dev/null; then
if [ ! -s "$response_file" ] || ! jq empty "$response_file" 2>/dev/null; then
echo "Error: invalid JSON for attempt $i"
rm -f tmp_$i.json
rm -f "$response_file"
continue
fi
if jq -e 'type == "array"' tmp_$i.json >/dev/null; then
node_count=$(jq 'length' tmp_$i.json)
if jq -e 'type == "array"' "$response_file" >/dev/null; then
node_count=$(jq 'length' "$response_file")
echo "Found $node_count nodes in attempt $i"
for j in $(seq 0 $((node_count - 1))); do
downloads=$(jq -r ".[$j].downloads // 0" tmp_$i.json)
name=$(jq -r ".[$j].name // \"\"" tmp_$i.json)
while IFS= read -r node_json; do
downloads=$(jq -r '.downloads // 0' <<< "$node_json")
name=$(jq -r '.name // ""' <<< "$node_json")
if ! [[ "$downloads" =~ ^[0-9]+$ ]]; then
downloads=0
@@ -56,13 +100,13 @@ jobs:
if [ "$found_valid_data" = false ] || [ "$downloads" -gt "$max_downloads" ]; then
found_valid_data=true
max_downloads=$downloads
top_node_json=$(jq ".[$j]" tmp_$i.json)
top_node_json=$node_json
echo "New maximum found: $downloads (node: $name)"
fi
done
done < <(jq -c '.[]' "$response_file")
else
downloads=$(jq -r '.downloads // 0' tmp_$i.json)
name=$(jq -r '.name // ""' tmp_$i.json)
downloads=$(jq -r '.downloads // 0' "$response_file")
name=$(jq -r '.name // ""' "$response_file")
if ! [[ "$downloads" =~ ^[0-9]+$ ]]; then
downloads=0
@@ -71,126 +115,206 @@ jobs:
if [ "$found_valid_data" = false ] || [ "$downloads" -gt "$max_downloads" ]; then
found_valid_data=true
max_downloads=$downloads
top_node_json=$(cat tmp_$i.json)
top_node_json=$(jq -c . "$response_file")
echo "New maximum found: $downloads (node: $name)"
fi
fi
rm -f tmp_$i.json
rm -f "$response_file"
done
if [ "$found_valid_data" = true ]; then
echo "$top_node_json" > top_modelresolver.json
echo "Highest download count: $max_downloads"
echo "Node details:"
jq . top_modelresolver.json
else
if [ "$found_valid_data" = false ]; then
echo "Error: no valid data found"
exit 1
fi
- name: create or update gist with top download
id: set_id
run: |
BADGE_DOC="badges/DOWNLOADS.md"
jq . <<< "$top_node_json" > "$DATA_FILE"
echo "Highest download count: $max_downloads"
jq . "$DATA_FILE"
if gh secret list | grep -q "MODELRESOLVER_GIST_ID"
then
echo "GIST_ID found"
echo "GIST=${{ secrets.MODELRESOLVER_GIST_ID }}" >> $GITHUB_OUTPUT
display_name=$(jq -r '.name // .id // empty' "$DATA_FILE")
publisher_id=$(jq -r '.publisher.id // empty' "$DATA_FILE")
node_slug=$(jq -r '(.id // empty) | ascii_downcase' "$DATA_FILE")
if gh gist view ${{ secrets.MODELRESOLVER_GIST_ID }} &>/dev/null; then
echo "Gist exists and will be updated"
else
echo "Gist does not exist, creating a new one"
gist_id=$(gh gist create top_modelresolver.json | awk -F / '{print $NF}')
echo $gist_id | gh secret set MODELRESOLVER_GIST_ID
echo "GIST=$gist_id" >> $GITHUB_OUTPUT
git rm --ignore-unmatch "$BADGE_DOC" MODELRESOLVER.md
fi
else
echo "Creating a new gist"
gist_id=$(gh gist create top_modelresolver.json | awk -F / '{print $NF}')
echo $gist_id | gh secret set MODELRESOLVER_GIST_ID
echo "GIST=$gist_id" >> $GITHUB_OUTPUT
fi
- name: create badge if needed
run: |
COUNT=$(jq '.downloads' top_modelresolver.json)
NAME=$(jq -r '.name' top_modelresolver.json)
BADGE_DOC="badges/DOWNLOADS.md"
if [ ! -f "$BADGE_DOC" ] || ! grep -q "Combined HTML (for-the-badge)" "$BADGE_DOC"; then
mkdir -p badges
shields="https://img.shields.io/badge/dynamic/json?color=informational&label=TopModelResolver&query=downloads&url="
shields_for_the_badge="https://img.shields.io/badge/dynamic/json?color=2F80ED&label=TopModelResolver&query=downloads&url="
comfy_badge="https://img.shields.io/badge/ComfyUI-1a1a1a?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAASFBMVEVHcEwYLtsYLtkXLtkXLdkYLtkWLdcFIdoAD95uerfI1XLR3mq3xIP8/yj0/zvw/0FSYMP5/zKMmKQtPNOuuozj8FOhrZW7x4FMWFFbAAAABnRSTlMAUrPX87KxijklAAAA00lEQVR4AX3SBw6DMAxA0UzbrIzO+9+02GkEpoWP9hPZZs06Hw75aI3k4W/+wkQtnGZNhF1I34BzalQcxkmasY0b9raklNcvLYU1GNiiOeVWauOa/XS526gRyzpV/7HeUOG9Jp6vcsvUrCPeKg/3KBKBQhoTD1dQggPWzPVfFOIgo85/kR4y6oB/8SlIEh7wvmTuKd3wgLVW1sTfRBoR7oWVqy/U2NcrWDYMINE7NUuJuoV+2fhaWmnbjzcOWnRv7XbiLh/Y9dNUqk2y0QcNwTu7wgf+/BhsPUhf4QAAAABJRU5ErkJggg=="
combined_downloads="https://img.shields.io/badge/dynamic/json?color=%230D2A4A&label=&query=downloads&url="
url="https://gist.githubusercontent.com/${{ github.actor }}/${{ steps.set_id.outputs.GIST }}/raw/top_modelresolver.json"
repo="https://registry.comfy.org/publishers/azornes/nodes/comfyui-model-resolver"
echo ''> "$BADGE_DOC"
echo '
**Markdown**
```markdown' >> "$BADGE_DOC"
echo "[![Top Model Resolver Node]($shields$url)]($repo)" >> "$BADGE_DOC"
echo '
```' >> "$BADGE_DOC"
echo "[![Top Model Resolver Node]($shields$url)]($repo)" >> "$BADGE_DOC"
echo '
**HTML**
```html' >> "$BADGE_DOC"
echo "<a href='$repo'><img alt='Top Model Resolver Node' src='$shields$url'></a>" >> "$BADGE_DOC"
echo '
```' >> "$BADGE_DOC"
echo "<a href='$repo'><img alt='Top Model Resolver Node' src='$shields$url'></a>" >> "$BADGE_DOC"
echo '
**HTML (for-the-badge)**
```html' >> "$BADGE_DOC"
echo "<a href='$repo'><img alt='Top Model Resolver Node' src='$shields_for_the_badge$url&style=for-the-badge'></a>" >> "$BADGE_DOC"
echo '```' >> "$BADGE_DOC"
echo "<a href='$repo'><img alt='Top Model Resolver Node' src='$shields_for_the_badge$url&style=for-the-badge'></a>" >> "$BADGE_DOC"
echo '
**Combined Markdown (for-the-badge)**
```markdown' >> "$BADGE_DOC"
echo "[![ComfyUI]($comfy_badge)![Downloads]($combined_downloads$url&style=for-the-badge)]($repo)" >> "$BADGE_DOC"
echo '
```' >> "$BADGE_DOC"
echo "[![ComfyUI]($comfy_badge)![Downloads]($combined_downloads$url&style=for-the-badge)]($repo)" >> "$BADGE_DOC"
echo '
**Combined HTML (for-the-badge)**
```html' >> "$BADGE_DOC"
echo "<a href='$repo'><img alt='ComfyUI' src='$comfy_badge'><img alt='Downloads' src='$combined_downloads$url&style=for-the-badge'></a>" >> "$BADGE_DOC"
echo '```' >> "$BADGE_DOC"
echo "<a href='$repo'><img alt='ComfyUI' src='$comfy_badge'><img alt='Downloads' src='$combined_downloads$url&style=for-the-badge'></a>" >> "$BADGE_DOC"
git add "$BADGE_DOC"
git config --global user.name "GitHub Action"
git config --global user.email "action@github.com"
git commit -m "Create or update Model Resolver downloads badge"
fi
- name: Update Gist
run: |
if jq empty top_modelresolver.json 2>/dev/null; then
content=$(jq -c . top_modelresolver.json)
echo "{\"description\": \"Top Model Resolver Node\", \"files\": {\"top_modelresolver.json\": {\"content\": $(jq -Rs . <<< "$content")}}}" > patch.json
curl -s -X PATCH \
--user "${{ github.actor }}:${{ secrets.SECRET_TOKEN }}" \
-H "Content-Type: application/json" \
-d @patch.json https://api.github.com/gists/${{ steps.set_id.outputs.GIST }}
else
echo "Error: invalid JSON in top_modelresolver.json"
if [ -z "$display_name" ] || [ -z "$publisher_id" ] || [ -z "$node_slug" ]; then
echo "::error title=Incomplete Registry response::The node name, publisher ID, or node ID is missing."
exit 1
fi
- name: Push
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
{
echo "COMFY_NODE_DISPLAY_NAME=$display_name"
echo "COMFY_PUBLISHER_ID=$publisher_id"
echo "COMFY_NODE_SLUG=$node_slug"
} >> "$GITHUB_ENV"
- name: Create or reuse downloads Gist
id: gist
run: |
gist_id="$COMFY_DOWNLOADS_GIST_ID"
save_gist_id=false
if [ -z "$gist_id" ]; then
gist_id=$(python - <<'PY'
from pathlib import Path
import os
import re
pattern = re.compile(
r"query=downloads.*?url=https://gist\.githubusercontent\.com/[^/]+/([0-9a-f]+)",
re.IGNORECASE,
)
for filename in (os.environ["BADGE_DOC"], "README.md"):
path = Path(filename)
if not path.is_file():
continue
match = pattern.search(path.read_text(encoding="utf-8"))
if match:
print(match.group(1))
break
PY
)
if [ -n "$gist_id" ]; then
echo "Found an existing downloads Gist in the badge documentation: $gist_id"
save_gist_id=true
fi
fi
if [ -n "$gist_id" ] && gh gist view "$gist_id" >/dev/null 2>&1; then
echo "Using existing Gist: $gist_id"
else
if [ -n "$gist_id" ]; then
echo "Configured Gist does not exist or is inaccessible; creating a new one."
else
echo "No Gist is configured; creating one."
fi
gist_url=$(gh gist create "$DATA_FILE" \
--desc "ComfyUI downloads for $COMFY_NODE_DISPLAY_NAME")
gist_id="${gist_url##*/}"
save_gist_id=true
fi
if [ "$save_gist_id" = true ]; then
if ! gh variable set COMFY_DOWNLOADS_GIST_ID --body "$gist_id"; then
echo "::error title=Cannot save Gist ID::Grant SECRET_TOKEN repository Actions variables write access."
exit 1
fi
echo "Saved COMFY_DOWNLOADS_GIST_ID=$gist_id"
fi
gist_filename=$(gh api "gists/$gist_id" --jq '
.files
| keys
| if index("comfyui_downloads.json") then
"comfyui_downloads.json"
else
(map(select(endswith(".json"))) | first // "comfyui_downloads.json")
end
')
gist_owner=$(gh api user --jq '.login')
echo "id=$gist_id" >> "$GITHUB_OUTPUT"
echo "filename=$gist_filename" >> "$GITHUB_OUTPUT"
echo "owner=$gist_owner" >> "$GITHUB_OUTPUT"
- name: Create or update badge document
id: badge
env:
GIST_ID: ${{ steps.gist.outputs.id }}
GIST_FILENAME: ${{ steps.gist.outputs.filename }}
GIST_OWNER: ${{ steps.gist.outputs.owner }}
run: |
mkdir -p "$(dirname "$BADGE_DOC")"
badge_label=$(jq -rn --arg value "$COMFY_NODE_DISPLAY_NAME" '$value | @uri')
registry_url="https://registry.comfy.org/publishers/${COMFY_PUBLISHER_ID}/nodes/${COMFY_NODE_SLUG}"
gist_url="https://gist.githubusercontent.com/${GIST_OWNER}/${GIST_ID}/raw/${GIST_FILENAME}"
shields="https://img.shields.io/badge/dynamic/json?color=informational&label=${badge_label}&query=downloads&url="
shields_for_the_badge="https://img.shields.io/badge/dynamic/json?color=2F80ED&label=${badge_label}&query=downloads&url="
comfy_badge="https://img.shields.io/badge/ComfyUI-1a1a1a?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAASFBMVEVHcEwYLtsYLtkXLtkXLdkYLtkWLdcFIdoAD95uerfI1XLR3mq3xIP8/yj0/zvw/0FSYMP5/zKMmKQtPNOuuozj8FOhrZW7x4FMWFFbAAAABnRSTlMAUrPX87KxijklAAAA00lEQVR4AX3SBw6DMAxA0UzbrIzO+9+02GkEpoWP9hPZZs06Hw75aI3k4W/+wkQtnGZNhF1I34BzalQcxkmasY0b9raklNcvLYU1GNiiOeVWauOa/XS526gRyzpV/7HeUOG9Jp6vcsvUrCPeKg/3KBKBQhoTD1dQggPWzPVfFOIgo85/kR4y6oB/8SlIEh7wvmTuKd3wgLVW1sTfRBoR7oWVqy/U2NcrWDYMINE7NUuJuoV+2fhaWmnbjzcOWnRv7XbiLh/Y9dNUqk2y0QcNwTu7wgf+/BhsPUhf4QAAAABJRU5ErkJggg=="
combined_downloads="https://img.shields.io/badge/dynamic/json?color=%230D2A4A&label=&query=downloads&url="
{
echo "**Markdown**"
echo
echo '```markdown'
echo "[![${COMFY_NODE_DISPLAY_NAME}](${shields}${gist_url})](${registry_url})"
echo '```'
echo
echo "[![${COMFY_NODE_DISPLAY_NAME}](${shields}${gist_url})](${registry_url})"
echo
echo "**HTML**"
echo
echo '```html'
echo "<a href='${registry_url}'><img alt='${COMFY_NODE_DISPLAY_NAME}' src='${shields}${gist_url}'></a>"
echo '```'
echo
echo "<a href='${registry_url}'><img alt='${COMFY_NODE_DISPLAY_NAME}' src='${shields}${gist_url}'></a>"
echo
echo "**HTML (for-the-badge)**"
echo
echo '```html'
echo "<a href='${registry_url}'><img alt='${COMFY_NODE_DISPLAY_NAME}' src='${shields_for_the_badge}${gist_url}&style=for-the-badge'></a>"
echo '```'
echo
echo "<a href='${registry_url}'><img alt='${COMFY_NODE_DISPLAY_NAME}' src='${shields_for_the_badge}${gist_url}&style=for-the-badge'></a>"
echo
echo "**Combined Markdown (for-the-badge)**"
echo
echo '```markdown'
echo "[![ComfyUI](${comfy_badge})![Downloads](${combined_downloads}${gist_url}&style=for-the-badge)](${registry_url})"
echo '```'
echo
echo "[![ComfyUI](${comfy_badge})![Downloads](${combined_downloads}${gist_url}&style=for-the-badge)](${registry_url})"
echo
echo "**Combined HTML (for-the-badge)**"
echo
echo '```html'
echo "<a href='${registry_url}'><img alt='ComfyUI' src='${comfy_badge}'><img alt='Downloads' src='${combined_downloads}${gist_url}&style=for-the-badge'></a>"
echo '```'
echo
echo "<a href='${registry_url}'><img alt='ComfyUI' src='${comfy_badge}'><img alt='Downloads' src='${combined_downloads}${gist_url}&style=for-the-badge'></a>"
} > "$BADGE_DOC"
if [ -n "$(git status --porcelain -- "$BADGE_DOC")" ]; then
git add "$BADGE_DOC"
git config user.name "GitHub Action"
git config user.email "action@github.com"
git commit -m "Create or update ComfyUI downloads badge"
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "Badge document is already up to date."
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
- name: Update Gist
env:
GIST_ID: ${{ steps.gist.outputs.id }}
GIST_FILENAME: ${{ steps.gist.outputs.filename }}
run: |
if ! jq empty "$DATA_FILE" 2>/dev/null; then
echo "Error: invalid JSON in $DATA_FILE"
exit 1
fi
content=$(jq -c . "$DATA_FILE")
jq -n \
--arg description "ComfyUI downloads for $COMFY_NODE_DISPLAY_NAME" \
--arg filename "$GIST_FILENAME" \
--arg content "$content" \
'{
description: $description,
files: {
($filename): {
content: $content
}
}
}' > gist_patch.json
gh api --method PATCH "gists/${GIST_ID}" --input gist_patch.json >/dev/null
- name: Push badge document
if: steps.badge.outputs.changed == 'true'
run: git push