diff --git a/.github/workflows/ComfyUIdownloads.yml b/.github/workflows/ComfyUIdownloads.yml
new file mode 100644
index 0000000..5ee8813
--- /dev/null
+++ b/.github/workflows/ComfyUIdownloads.yml
@@ -0,0 +1,161 @@
+name: Model Resolver Top Downloads Badge
+
+on:
+ schedule:
+ - cron: "0 0,8,16 * * *"
+ workflow_dispatch:
+
+permissions:
+ contents: write
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: gh login
+ run: echo "${{ secrets.SECRET_TOKEN }}" | gh auth login --with-token
+
+ - name: Query Model Resolver API and find top download
+ run: |
+ max_downloads=0
+ top_node_json="{}"
+ node_id="comfyui-model-resolver"
+
+ for i in {1..3}; do
+ echo "Pobieranie danych z próby $i..."
+ curl -s "https://api.comfy.org/nodes/${node_id}" > tmp_$i.json
+
+ if [ ! -s tmp_$i.json ] || ! jq empty tmp_$i.json 2>/dev/null; then
+ echo "Błąd: Nieprawidłowy JSON dla próby $i"
+ continue
+ fi
+
+ if jq -e 'type == "array"' tmp_$i.json >/dev/null; then
+ node_count=$(jq 'length' tmp_$i.json)
+ echo "Znaleziono $node_count węzłów w próbie $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)
+
+ if [ "$downloads" -gt "$max_downloads" ]; then
+ max_downloads=$downloads
+ top_node_json=$(jq ".[$j]" tmp_$i.json)
+ echo "Nowe maksimum znalezione: $downloads (węzeł: $name)"
+ fi
+ done
+ else
+ downloads=$(jq -r '.downloads // 0' tmp_$i.json)
+ name=$(jq -r '.name // ""' tmp_$i.json)
+
+ if [ "$downloads" -gt "$max_downloads" ]; then
+ max_downloads=$downloads
+ top_node_json=$(cat tmp_$i.json)
+ echo "Nowe maksimum znalezione: $downloads (węzeł: $name)"
+ fi
+ fi
+
+ rm -f tmp_$i.json
+ done
+
+ if [ "$max_downloads" -gt 0 ]; then
+ echo "$top_node_json" > top_modelresolver.json
+ echo "Najwyższa liczba pobrań: $max_downloads"
+ echo "Szczegóły węzła:"
+ jq . top_modelresolver.json
+ else
+ echo "Błąd: Nie znaleziono żadnych prawidłowych danych"
+ echo '{"name": "ComfyUI Model Resolver", "downloads": 0}' > top_modelresolver.json
+ fi
+
+ - name: create or update gist with top download
+ id: set_id
+ run: |
+ BADGE_DOC="badges/DOWNLOADS.md"
+
+ if gh secret list | grep -q "MODELRESOLVER_GIST_ID"
+ then
+ echo "GIST_ID found"
+ echo "GIST=${{ secrets.MODELRESOLVER_GIST_ID }}" >> $GITHUB_OUTPUT
+
+ if gh gist view ${{ secrets.MODELRESOLVER_GIST_ID }} &>/dev/null; then
+ echo "Gist istnieje, będzie zaktualizowany"
+ else
+ echo "Gist nie istnieje, tworzenie nowego"
+ 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 "Tworzenie nowego 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" ]; 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="
+ url="https://gist.githubusercontent.com/${{ github.actor }}/${{ steps.set_id.outputs.GIST }}/raw/top_modelresolver.json"
+ repo="https://comfy.org"
+ echo ''> "$BADGE_DOC"
+ echo '
+ **Markdown**
+
+ ```markdown' >> "$BADGE_DOC"
+ echo "[]($repo)" >> "$BADGE_DOC"
+ echo '
+ ```' >> "$BADGE_DOC"
+ echo "[]($repo)" >> "$BADGE_DOC"
+ echo '
+
+ **HTML**
+ ```html' >> "$BADGE_DOC"
+ echo "
" >> "$BADGE_DOC"
+ echo '
+ ```' >> "$BADGE_DOC"
+ echo "
" >> "$BADGE_DOC"
+ echo '
+
+ **HTML (for-the-badge)**
+ ```html' >> "$BADGE_DOC"
+ echo "
" >> "$BADGE_DOC"
+ echo '```' >> "$BADGE_DOC"
+ echo "
" >> "$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 Model Resolver 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 "Błąd: Nieprawidłowy JSON w top_modelresolver.json"
+ exit 1
+ fi
+
+ - name: Push
+ uses: ad-m/github-push-action@master
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/clone.yml b/.github/workflows/clone.yml
index 3b885c5..936a3a4 100644
--- a/.github/workflows/clone.yml
+++ b/.github/workflows/clone.yml
@@ -28,6 +28,8 @@ jobs:
- name: create gist and download previous count
id: set_id
run: |
+ BADGE_DOC="badges/CLONE.md"
+
if gh secret list | grep -q "GIST_ID"
then
echo "GIST_ID found"
@@ -39,7 +41,7 @@ jobs:
echo $gist_id | gh secret set GIST_ID
echo "GIST=$gist_id" >> $GITHUB_OUTPUT
cp clone.json clone_before.json
- git rm --ignore-unmatch CLONE.md
+ git rm --ignore-unmatch "$BADGE_DOC" CLONE.md
fi
else
echo "GIST_ID not found. Creating a gist..."
@@ -56,6 +58,8 @@ jobs:
- name: Update gist with latest count
run: |
+ BADGE_DOC="badges/CLONE.md"
+
content=$(sed -e 's/\\/\\\\/g' -e 's/\t/\\t/g' -e 's/\"/\\"/g' -e 's/\r//g' "clone.json" | sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g')
echo '{"description": "${{ github.repository }} clone statistics", "files": {"clone.json": {"content": "'"$content"'"}}}' > post_clone.json
curl -s -X PATCH \
@@ -63,37 +67,38 @@ jobs:
-H "Content-Type: application/json" \
-d @post_clone.json https://api.github.com/gists/${{ steps.set_id.outputs.GIST }} > /dev/null 2>&1
- if [ ! -f CLONE.md ]; then
+ if [ ! -f "$BADGE_DOC" ]; then
+ mkdir -p badges
shields="https://img.shields.io/badge/dynamic/json?color=success&label=Clone&query=count&url="
shields_for_the_badge="https://img.shields.io/badge/dynamic/json?color=2F80ED&label=Clone&query=count&url="
url="https://gist.githubusercontent.com/${{ github.actor }}/${{ steps.set_id.outputs.GIST }}/raw/clone.json"
repo="https://github.com/MShawon/github-clone-count-badge"
- echo ''> CLONE.md
+ echo ''> "$BADGE_DOC"
echo '
**Markdown**
- ```markdown' >> CLONE.md
- echo "[]($repo)" >> CLONE.md
+ ```markdown' >> "$BADGE_DOC"
+ echo "[]($repo)" >> "$BADGE_DOC"
echo '
- ```' >> CLONE.md
- echo "[]($repo)" >> CLONE.md
+ ```' >> "$BADGE_DOC"
+ echo "[]($repo)" >> "$BADGE_DOC"
echo '
**HTML**
- ```html' >> CLONE.md
- echo "
" >> CLONE.md
+ ```html' >> "$BADGE_DOC"
+ echo "
" >> "$BADGE_DOC"
echo '
- ```' >> CLONE.md
- echo "
" >> CLONE.md
+ ```' >> "$BADGE_DOC"
+ echo "
" >> "$BADGE_DOC"
echo '
**HTML (for-the-badge)**
- ```html' >> CLONE.md
- echo "
" >> CLONE.md
- echo '```' >> CLONE.md
- echo "
" >> CLONE.md
+ ```html' >> "$BADGE_DOC"
+ echo "
" >> "$BADGE_DOC"
+ echo '```' >> "$BADGE_DOC"
+ echo "
" >> "$BADGE_DOC"
- git add CLONE.md
+ git add "$BADGE_DOC"
git config --global user.name "GitHub Action"
git config --global user.email "action@github.com"
git commit -m "create clone count badge"
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..537b012
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,30 @@
+name: Publish to Comfy Registry
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ paths:
+ - "pyproject.toml"
+
+permissions:
+ contents: read
+
+concurrency:
+ group: comfy-registry-publish-${{ github.ref }}
+ cancel-in-progress: false
+
+jobs:
+ publish-node:
+ name: Publish Custom Node to registry
+ runs-on: ubuntu-latest
+ if: ${{ github.repository == 'Azornes/Comfyui-Model-Resolver' }}
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v4
+
+ - name: Publish Custom Node
+ uses: Comfy-Org/publish-node-action@main
+ with:
+ personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..fd330c8
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,94 @@
+name: Release
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ paths:
+ - "pyproject.toml"
+
+permissions:
+ contents: write
+
+concurrency:
+ group: release-${{ github.ref }}
+ cancel-in-progress: false
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Read project metadata
+ id: metadata
+ run: |
+ python - <<'PY' >> "$GITHUB_OUTPUT"
+ import re
+ import tomllib
+
+ with open("pyproject.toml", "rb") as handle:
+ data = tomllib.load(handle)
+
+ project = data["project"]
+ version = str(project["version"]).strip()
+ name = str(project["name"]).strip()
+
+ if not re.fullmatch(r"\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?", version):
+ raise SystemExit(f"Invalid semantic version in pyproject.toml: {version}")
+
+ print(f"project_name={name}")
+ print(f"version={version}")
+ print(f"tag=v{version}")
+ PY
+
+ - name: Check if tag for this version already exists
+ id: tag_check
+ run: |
+ TAG="${{ steps.metadata.outputs.tag }}"
+ git fetch --force --tags
+
+ if git rev-parse --verify --quiet "refs/tags/$TAG" >/dev/null; then
+ echo "Tag $TAG already exists. Skipping release."
+ echo "exists=true" >> $GITHUB_OUTPUT
+ else
+ echo "exists=false" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Build release notes
+ id: notes
+ if: steps.tag_check.outputs.exists != 'true'
+ run: |
+ CURRENT_TAG="${{ steps.metadata.outputs.tag }}"
+ PREVIOUS_TAG="$(git tag --list 'v[0-9]*' --sort=-v:refname | grep -vx "$CURRENT_TAG" | head -n 1 || true)"
+
+ if [ -n "$PREVIOUS_TAG" ]; then
+ RANGE="$PREVIOUS_TAG..HEAD"
+ HEADER="Changes since $PREVIOUS_TAG"
+ else
+ RANGE="HEAD"
+ HEADER="Initial release"
+ fi
+
+ {
+ echo "body<> "$GITHUB_OUTPUT"
+
+ - name: Create GitHub Release
+ if: steps.tag_check.outputs.exists != 'true'
+ uses: softprops/action-gh-release@v2
+ with:
+ tag_name: ${{ steps.metadata.outputs.tag }}
+ name: ComfyUI Model Resolver ${{ steps.metadata.outputs.tag }}
+ body: ${{ steps.notes.outputs.body }}
+ generate_release_notes: true
diff --git a/__init__.py b/__init__.py
index 84ef73d..393e96b 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,8 +1,7 @@
"""
-@author: Model Resolver Team
+@author: Azornes
@title: ComfyUI Model Resolver
-@nickname: Model Resolver
-@version: 1.1.0
+@version: 1.0.0
@description: Extension for resolving missing models and downloading from HuggingFace/CivitAI
"""
diff --git a/CLONE.md b/badges/CLONE.md
similarity index 100%
rename from CLONE.md
rename to badges/CLONE.md
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..c0a18f2
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,17 @@
+[project]
+name = "Comfyui-Model-Resolver"
+description = "ComfyUI extension for automatically resolving missing models in loaded workflows. It features intelligent local fuzzy matching, direct cloud downloads, background download tracking, and automated in-place workflow updating."
+version = "1.0.0"
+license = { text = "MIT License" }
+dynamic = ["dependencies"]
+
+[project.urls]
+Repository = "https://github.com/Azornes/Comfyui-Model-Resolver"
+
+[tool.setuptools.dynamic]
+dependencies = { file = ["requirements.txt"] }
+
+[tool.comfy]
+PublisherId = "azornes"
+DisplayName = "Comfyui-Model-Resolver"
+Icon = ""