2025-11-22 02:13:07 +01:00
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
#
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# HuggingFace Model Downloader - A Beautiful CLI Tool
|
|
|
|
|
|
# Downloads AI models from HuggingFace and creates symlinks to output directories
|
2025-11-22 02:13:07 +01:00
|
|
|
|
#
|
2025-11-25 16:46:44 +01:00
|
|
|
|
# Usage: ./artifact_huggingface_download.sh [COMMAND] [OPTIONS]
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
#
|
2025-11-25 16:46:44 +01:00
|
|
|
|
# Commands:
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# download Download models to cache directory (default)
|
|
|
|
|
|
# link Create symlinks from cache to output directory
|
|
|
|
|
|
# verify Verify symlinks in output directory
|
2025-11-25 16:46:44 +01:00
|
|
|
|
#
|
|
|
|
|
|
# Options:
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# -c, --config FILE Configuration YAML file (required)
|
|
|
|
|
|
# --cache-dir DIR Cache directory
|
|
|
|
|
|
# --output-dir DIR Output/installation directory
|
|
|
|
|
|
# --category CAT1,CAT2 Filter by category (comma-separated)
|
|
|
|
|
|
# --repo-id ID1,ID2 Filter by repo_id (comma-separated)
|
|
|
|
|
|
# --auth-token TOKEN HuggingFace token
|
|
|
|
|
|
# -n, --dry-run Show what would be done
|
|
|
|
|
|
# -h, --help Show help
|
2025-11-22 02:13:07 +01:00
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# COLOR PALETTE - Beautiful Terminal Colors
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
RESET='\033[0m'
|
|
|
|
|
|
|
|
|
|
|
|
# Foreground Colors
|
|
|
|
|
|
RED='\033[0;31m'
|
|
|
|
|
|
GREEN='\033[0;32m'
|
|
|
|
|
|
YELLOW='\033[0;33m'
|
|
|
|
|
|
BLUE='\033[0;34m'
|
|
|
|
|
|
MAGENTA='\033[0;35m'
|
|
|
|
|
|
CYAN='\033[0;36m'
|
|
|
|
|
|
|
|
|
|
|
|
# Bold
|
|
|
|
|
|
BOLD_RED='\033[1;31m'
|
|
|
|
|
|
BOLD_GREEN='\033[1;32m'
|
|
|
|
|
|
BOLD_YELLOW='\033[1;33m'
|
|
|
|
|
|
BOLD_BLUE='\033[1;34m'
|
|
|
|
|
|
BOLD_MAGENTA='\033[1;35m'
|
|
|
|
|
|
BOLD_CYAN='\033[1;36m'
|
|
|
|
|
|
BOLD_WHITE='\033[1;37m'
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Background
|
2025-11-22 02:13:07 +01:00
|
|
|
|
BG_CYAN='\033[46m'
|
|
|
|
|
|
|
|
|
|
|
|
# Styles
|
|
|
|
|
|
DIM='\033[2m'
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# UNICODE CHARACTERS
|
2025-11-22 02:13:07 +01:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
CHECK_MARK="✓"
|
|
|
|
|
|
CROSS_MARK="✗"
|
|
|
|
|
|
ROCKET="🚀"
|
|
|
|
|
|
DOWNLOAD="⬇️"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
LINK_ICON="🔗"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
WARNING="⚠️"
|
|
|
|
|
|
INFO="ℹ️"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
SPARKLES="✨"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
ARROW_RIGHT="→"
|
|
|
|
|
|
BOX_LIGHT="─"
|
|
|
|
|
|
BOX_DOUBLE="═"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
PACKAGE="📦"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# CONFIGURATION
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
CONFIG_FILE=""
|
|
|
|
|
|
COMMAND="download"
|
|
|
|
|
|
DRY_RUN=false
|
|
|
|
|
|
CATEGORY_FILTER=""
|
|
|
|
|
|
REPO_ID_FILTER=""
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Default directories - detect RunPod or local
|
2025-11-22 17:53:18 +01:00
|
|
|
|
if [[ -d "/workspace" ]]; then
|
|
|
|
|
|
CACHE_DIR="${CACHE_DIR:-/workspace/huggingface_cache}"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
OUTPUT_DIR="${OUTPUT_DIR:-/workspace/ComfyUI/models}"
|
2025-11-22 17:53:18 +01:00
|
|
|
|
else
|
2025-11-26 15:01:27 +01:00
|
|
|
|
CACHE_DIR="${CACHE_DIR:-${HOME}/.cache/huggingface/hub}"
|
|
|
|
|
|
OUTPUT_DIR="${OUTPUT_DIR:-${HOME}/ComfyUI/models}"
|
2025-11-22 17:53:18 +01:00
|
|
|
|
fi
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# HuggingFace token from environment
|
|
|
|
|
|
HF_TOKEN="${HF_TOKEN:-}"
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Try to load from .env files
|
|
|
|
|
|
load_env_token() {
|
|
|
|
|
|
if [[ -n "$HF_TOKEN" ]]; then
|
|
|
|
|
|
return 0
|
|
|
|
|
|
fi
|
2025-11-25 16:46:44 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local env_files=(
|
|
|
|
|
|
"${HOME}/.env"
|
|
|
|
|
|
"${HOME}/Projects/runpod/.env"
|
|
|
|
|
|
"${HOME}/Projects/runpod/ai/.env"
|
|
|
|
|
|
"/workspace/.env"
|
|
|
|
|
|
"/workspace/ai/.env"
|
|
|
|
|
|
)
|
2025-11-22 16:05:12 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
for env_file in "${env_files[@]}"; do
|
|
|
|
|
|
if [[ -f "$env_file" ]]; then
|
|
|
|
|
|
local token
|
|
|
|
|
|
token=$(grep "^HF_TOKEN=" "$env_file" 2>/dev/null | cut -d'=' -f2- | tr -d '"' | tr -d "'" || true)
|
|
|
|
|
|
if [[ -n "$token" ]]; then
|
|
|
|
|
|
HF_TOKEN="$token"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
}
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# LOGGING FUNCTIONS
|
2025-11-22 02:13:07 +01:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
print_banner() {
|
|
|
|
|
|
local text="$1"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local width=70
|
|
|
|
|
|
local text_len=${#text}
|
|
|
|
|
|
local padding=$(( (width - text_len) / 2 ))
|
|
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
echo -e "${BOLD_CYAN}${BOX_DOUBLE}$(printf '%0.s═' $(seq 1 $width))${BOX_DOUBLE}${RESET}"
|
|
|
|
|
|
echo -e "${BOLD_CYAN}║$(printf '%*s' $padding '')${BOLD_MAGENTA}${text}$(printf '%*s' $((width - padding - text_len)) '')${BOLD_CYAN}║${RESET}"
|
|
|
|
|
|
echo -e "${BOLD_CYAN}${BOX_DOUBLE}$(printf '%0.s═' $(seq 1 $width))${BOX_DOUBLE}${RESET}"
|
|
|
|
|
|
echo ""
|
2025-11-22 02:13:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print_section() {
|
|
|
|
|
|
local text="$1"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
echo -e "\n${BOLD_CYAN}» ${text}${RESET}"
|
|
|
|
|
|
echo -e "${CYAN}$(printf '%0.s─' $(seq 1 70))${RESET}"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print_success() {
|
|
|
|
|
|
echo -e "${BOLD_GREEN}${CHECK_MARK} $1${RESET}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print_error() {
|
|
|
|
|
|
echo -e "${BOLD_RED}${CROSS_MARK} $1${RESET}" >&2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print_warning() {
|
|
|
|
|
|
echo -e "${BOLD_YELLOW}${WARNING} $1${RESET}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print_info() {
|
|
|
|
|
|
echo -e "${BOLD_CYAN}${INFO} $1${RESET}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print_step() {
|
|
|
|
|
|
local current="$1"
|
|
|
|
|
|
local total="$2"
|
|
|
|
|
|
local text="$3"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
echo -e "${BOLD_BLUE}[${current}/${total}]${RESET} ${CYAN}${PACKAGE}${RESET} ${text}"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print_detail() {
|
|
|
|
|
|
echo -e " ${DIM}${CYAN}${ARROW_RIGHT} $1${RESET}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
show_progress() {
|
|
|
|
|
|
local current="$1"
|
|
|
|
|
|
local total="$2"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local width=40
|
2025-11-22 02:13:07 +01:00
|
|
|
|
local percentage=$((current * 100 / total))
|
|
|
|
|
|
local filled=$((current * width / total))
|
|
|
|
|
|
local empty=$((width - filled))
|
|
|
|
|
|
|
|
|
|
|
|
printf "\r ${BOLD_CYAN}Progress: ${RESET}["
|
2025-11-26 15:01:27 +01:00
|
|
|
|
printf "${BG_CYAN}${BOLD_WHITE}%${filled}s${RESET}" | tr ' ' '█'
|
2025-11-22 02:13:07 +01:00
|
|
|
|
printf "${DIM}%${empty}s${RESET}" | tr ' ' '░'
|
|
|
|
|
|
printf "] ${BOLD_YELLOW}%3d%%${RESET} ${DIM}(%d/%d)${RESET}" "$percentage" "$current" "$total"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# YAML PARSING (using yq)
|
|
|
|
|
|
# ============================================================================
|
2025-11-25 16:46:44 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
check_yq() {
|
|
|
|
|
|
if ! command -v yq &>/dev/null; then
|
|
|
|
|
|
print_error "yq is not installed. Please install yq first."
|
|
|
|
|
|
print_info "Install: https://github.com/mikefarah/yq"
|
|
|
|
|
|
exit 1
|
2025-11-25 16:46:44 +01:00
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Get total count of models
|
|
|
|
|
|
get_model_count() {
|
|
|
|
|
|
local config="$1"
|
|
|
|
|
|
yq eval '. | length' "$config" 2>/dev/null || echo "0"
|
2025-11-22 17:20:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Get model field at index
|
|
|
|
|
|
get_model_field() {
|
|
|
|
|
|
local config="$1"
|
|
|
|
|
|
local index="$2"
|
|
|
|
|
|
local field="$3"
|
|
|
|
|
|
local value
|
|
|
|
|
|
value=$(yq eval ".[$index].$field // \"\"" "$config" 2>/dev/null)
|
|
|
|
|
|
echo "$value" | sed 's/^"//;s/"$//'
|
|
|
|
|
|
}
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Get files array length for a model
|
|
|
|
|
|
get_files_count() {
|
|
|
|
|
|
local config="$1"
|
|
|
|
|
|
local index="$2"
|
|
|
|
|
|
yq eval ".[$index].files | length" "$config" 2>/dev/null || echo "0"
|
|
|
|
|
|
}
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Get file mapping at index
|
|
|
|
|
|
get_file_field() {
|
|
|
|
|
|
local config="$1"
|
|
|
|
|
|
local model_index="$2"
|
|
|
|
|
|
local file_index="$3"
|
|
|
|
|
|
local field="$4"
|
|
|
|
|
|
local value
|
|
|
|
|
|
value=$(yq eval ".[$model_index].files[$file_index].$field // \"\"" "$config" 2>/dev/null)
|
|
|
|
|
|
echo "$value" | sed 's/^"//;s/"$//'
|
|
|
|
|
|
}
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Check if model matches filters
|
|
|
|
|
|
matches_filters() {
|
|
|
|
|
|
local repo_id="$1"
|
|
|
|
|
|
local category="$2"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Check category filter
|
|
|
|
|
|
if [[ -n "$CATEGORY_FILTER" ]]; then
|
|
|
|
|
|
local match=false
|
|
|
|
|
|
IFS=',' read -ra cats <<< "$CATEGORY_FILTER"
|
|
|
|
|
|
for cat in "${cats[@]}"; do
|
|
|
|
|
|
cat=$(echo "$cat" | xargs)
|
|
|
|
|
|
if [[ "$category" == "$cat" ]]; then
|
|
|
|
|
|
match=true
|
|
|
|
|
|
break
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
if [[ "$match" == false ]]; then
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
2025-11-22 02:13:07 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Check repo_id filter
|
|
|
|
|
|
if [[ -n "$REPO_ID_FILTER" ]]; then
|
|
|
|
|
|
local match=false
|
|
|
|
|
|
IFS=',' read -ra repos <<< "$REPO_ID_FILTER"
|
|
|
|
|
|
for repo in "${repos[@]}"; do
|
|
|
|
|
|
repo=$(echo "$repo" | xargs)
|
|
|
|
|
|
if [[ "$repo_id" == "$repo" ]]; then
|
|
|
|
|
|
match=true
|
|
|
|
|
|
break
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
if [[ "$match" == false ]]; then
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
2025-11-22 02:13:07 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
return 0
|
2025-11-22 02:13:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# DOWNLOAD FUNCTIONS
|
|
|
|
|
|
# ============================================================================
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
download_file() {
|
|
|
|
|
|
local repo_id="$1"
|
|
|
|
|
|
local source="$2"
|
|
|
|
|
|
|
|
|
|
|
|
# Convert repo_id to cache path (replace / with --)
|
|
|
|
|
|
local cache_repo_dir="${CACHE_DIR}/${repo_id}"
|
|
|
|
|
|
local source_dir
|
|
|
|
|
|
source_dir=$(dirname "$source")
|
|
|
|
|
|
local output_dir="${cache_repo_dir}"
|
|
|
|
|
|
if [[ "$source_dir" != "." ]]; then
|
|
|
|
|
|
output_dir="${cache_repo_dir}/${source_dir}"
|
|
|
|
|
|
fi
|
|
|
|
|
|
local filename
|
|
|
|
|
|
filename=$(basename "$source")
|
|
|
|
|
|
local output_path="${output_dir}/${filename}"
|
|
|
|
|
|
|
|
|
|
|
|
print_detail "File: ${BOLD_WHITE}${source}${RESET}"
|
|
|
|
|
|
print_detail "Output: ${CYAN}${output_path}${RESET}"
|
|
|
|
|
|
|
|
|
|
|
|
# Check if already exists
|
|
|
|
|
|
if [[ -f "$output_path" ]]; then
|
|
|
|
|
|
local size
|
|
|
|
|
|
size=$(du -h "$output_path" | cut -f1)
|
|
|
|
|
|
print_success "Already downloaded: ${filename} (${size})"
|
|
|
|
|
|
return 0
|
2025-11-22 02:13:07 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Dry-run mode
|
|
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
|
|
|
|
print_info "DRY-RUN: Would download ${BOLD_WHITE}${source}${RESET}"
|
|
|
|
|
|
return 0
|
2025-11-22 02:13:07 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Create output directory
|
|
|
|
|
|
mkdir -p "$output_dir"
|
2025-11-25 16:46:44 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Build download URL
|
|
|
|
|
|
local url="https://huggingface.co/${repo_id}/resolve/main/${source}"
|
|
|
|
|
|
print_detail "Downloading from HuggingFace..."
|
|
|
|
|
|
|
|
|
|
|
|
# Download with curl (with resume support)
|
|
|
|
|
|
local curl_args=(-L -C - --progress-bar -o "$output_path")
|
|
|
|
|
|
if [[ -n "$HF_TOKEN" ]]; then
|
|
|
|
|
|
curl_args+=(-H "Authorization: Bearer ${HF_TOKEN}")
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if curl "${curl_args[@]}" "$url" 2>&1; then
|
|
|
|
|
|
if [[ -f "$output_path" ]] && [[ -s "$output_path" ]]; then
|
|
|
|
|
|
local size
|
|
|
|
|
|
size=$(du -h "$output_path" | cut -f1)
|
|
|
|
|
|
print_success "Downloaded ${BOLD_WHITE}${filename}${RESET} (${size})"
|
|
|
|
|
|
return 0
|
2025-11-25 13:33:37 +01:00
|
|
|
|
fi
|
2025-11-22 02:13:07 +01:00
|
|
|
|
fi
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_error "Failed to download ${source}"
|
|
|
|
|
|
rm -f "$output_path" 2>/dev/null || true
|
|
|
|
|
|
return 1
|
2025-11-22 02:13:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
download_model() {
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local config="$1"
|
|
|
|
|
|
local index="$2"
|
|
|
|
|
|
local repo_id="$3"
|
|
|
|
|
|
local description="$4"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
|
|
|
|
|
print_detail "Repository: ${BOLD_WHITE}${repo_id}${RESET}"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
[[ -n "$description" ]] && print_detail "Description: ${description}"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local files_count
|
|
|
|
|
|
files_count=$(get_files_count "$config" "$index")
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ "$files_count" == "0" ]]; then
|
|
|
|
|
|
print_warning "No files defined for ${repo_id}"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
2025-11-25 19:45:32 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local succeeded=0
|
|
|
|
|
|
local failed=0
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
for ((f=0; f<files_count; f++)); do
|
|
|
|
|
|
local source
|
|
|
|
|
|
source=$(get_file_field "$config" "$index" "$f" "source")
|
2025-11-25 19:45:32 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ -z "$source" ]]; then
|
|
|
|
|
|
continue
|
2025-11-25 19:24:41 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if download_file "$repo_id" "$source"; then
|
|
|
|
|
|
succeeded=$((succeeded+1))
|
|
|
|
|
|
else
|
|
|
|
|
|
failed=$((failed+1))
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ $failed -eq 0 ]]; then
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
return 0
|
|
|
|
|
|
else
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# LINK FUNCTIONS
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
link_file() {
|
2025-11-25 16:46:44 +01:00
|
|
|
|
local repo_id="$1"
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local source="$2"
|
|
|
|
|
|
local dest="$3"
|
2025-11-25 16:46:44 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local cache_repo_dir="${CACHE_DIR}/${repo_id}"
|
|
|
|
|
|
local source_path="${cache_repo_dir}/${source}"
|
|
|
|
|
|
local link_path="${OUTPUT_DIR}/${dest}"
|
|
|
|
|
|
local link_dir
|
|
|
|
|
|
link_dir=$(dirname "$link_path")
|
2025-11-25 16:46:44 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_detail "Source: ${CYAN}${source_path}${RESET}"
|
|
|
|
|
|
print_detail "Target: ${CYAN}${link_path}${RESET}"
|
2025-11-25 16:46:44 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Check if source exists
|
|
|
|
|
|
if [[ ! -f "$source_path" ]]; then
|
|
|
|
|
|
print_warning "Source file not found: ${source}"
|
|
|
|
|
|
return 1
|
2025-11-25 19:24:41 +01:00
|
|
|
|
fi
|
2025-11-25 16:46:44 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Dry-run mode
|
2025-11-25 16:46:44 +01:00
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_info "DRY-RUN: Would link ${BOLD_WHITE}${source}${RESET} → ${dest}"
|
2025-11-25 16:46:44 +01:00
|
|
|
|
return 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Create target directory
|
|
|
|
|
|
mkdir -p "$link_dir"
|
2025-11-25 19:24:41 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Remove existing symlink
|
|
|
|
|
|
if [[ -L "$link_path" ]]; then
|
|
|
|
|
|
rm -f "$link_path"
|
|
|
|
|
|
elif [[ -e "$link_path" ]]; then
|
|
|
|
|
|
print_warning "File exists (not a symlink): ${dest}"
|
|
|
|
|
|
return 1
|
2025-11-25 19:24:41 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Create symlink
|
|
|
|
|
|
ln -s "$source_path" "$link_path"
|
|
|
|
|
|
print_success "Linked: ${LINK_ICON} ${dest}"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
2025-11-25 19:24:41 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
link_model() {
|
|
|
|
|
|
local config="$1"
|
|
|
|
|
|
local index="$2"
|
|
|
|
|
|
local repo_id="$3"
|
2025-11-25 19:24:41 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_detail "Repository: ${BOLD_WHITE}${repo_id}${RESET}"
|
2025-11-25 19:24:41 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local files_count
|
|
|
|
|
|
files_count=$(get_files_count "$config" "$index")
|
2025-11-25 16:46:44 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ "$files_count" == "0" ]]; then
|
|
|
|
|
|
print_warning "No files defined for ${repo_id}"
|
2025-11-25 16:46:44 +01:00
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local succeeded=0
|
|
|
|
|
|
local failed=0
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
for ((f=0; f<files_count; f++)); do
|
|
|
|
|
|
local source dest
|
|
|
|
|
|
source=$(get_file_field "$config" "$index" "$f" "source")
|
|
|
|
|
|
dest=$(get_file_field "$config" "$index" "$f" "dest")
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ -z "$source" ]]; then
|
|
|
|
|
|
continue
|
2025-11-25 13:33:37 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# If dest is empty, use source as dest
|
|
|
|
|
|
if [[ -z "$dest" ]]; then
|
|
|
|
|
|
dest="$source"
|
2025-11-25 14:45:57 +01:00
|
|
|
|
fi
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if link_file "$repo_id" "$source" "$dest"; then
|
|
|
|
|
|
succeeded=$((succeeded+1))
|
|
|
|
|
|
else
|
|
|
|
|
|
failed=$((failed+1))
|
2025-11-25 13:33:37 +01:00
|
|
|
|
fi
|
2025-11-26 15:01:27 +01:00
|
|
|
|
done
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ $failed -eq 0 ]]; then
|
|
|
|
|
|
return 0
|
2025-11-25 13:33:37 +01:00
|
|
|
|
else
|
2025-11-26 15:01:27 +01:00
|
|
|
|
return 1
|
2025-11-25 13:33:37 +01:00
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# VERIFY FUNCTIONS
|
|
|
|
|
|
# ============================================================================
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
verify_model() {
|
|
|
|
|
|
local config="$1"
|
|
|
|
|
|
local index="$2"
|
|
|
|
|
|
local repo_id="$3"
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
echo -e " ${BOLD_WHITE}${repo_id}${RESET}"
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local files_count
|
|
|
|
|
|
files_count=$(get_files_count "$config" "$index")
|
|
|
|
|
|
|
|
|
|
|
|
if [[ "$files_count" == "0" ]]; then
|
|
|
|
|
|
echo -e " ${BOLD_YELLOW}No files defined${RESET}"
|
|
|
|
|
|
return 1
|
2025-11-25 13:33:37 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
for ((f=0; f<files_count; f++)); do
|
|
|
|
|
|
local source dest
|
|
|
|
|
|
source=$(get_file_field "$config" "$index" "$f" "source")
|
|
|
|
|
|
dest=$(get_file_field "$config" "$index" "$f" "dest")
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ -z "$source" ]]; then
|
|
|
|
|
|
continue
|
|
|
|
|
|
fi
|
|
|
|
|
|
if [[ -z "$dest" ]]; then
|
|
|
|
|
|
dest="$source"
|
|
|
|
|
|
fi
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local cache_path="${CACHE_DIR}/${repo_id}/${source}"
|
|
|
|
|
|
local link_path="${OUTPUT_DIR}/${dest}"
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local cache_status="${BOLD_RED}${CROSS_MARK}${RESET}"
|
|
|
|
|
|
local link_status="${BOLD_RED}${CROSS_MARK}${RESET}"
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Check cache
|
|
|
|
|
|
if [[ -f "$cache_path" ]]; then
|
|
|
|
|
|
local size
|
|
|
|
|
|
size=$(du -h "$cache_path" | cut -f1)
|
|
|
|
|
|
cache_status="${BOLD_GREEN}${CHECK_MARK}${RESET} (${size})"
|
|
|
|
|
|
fi
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Check symlink
|
|
|
|
|
|
if [[ -L "$link_path" ]]; then
|
|
|
|
|
|
if [[ -e "$link_path" ]]; then
|
|
|
|
|
|
link_status="${BOLD_GREEN}${CHECK_MARK}${RESET}"
|
2025-11-25 13:33:37 +01:00
|
|
|
|
else
|
2025-11-26 15:01:27 +01:00
|
|
|
|
link_status="${BOLD_YELLOW}${WARNING}${RESET} (broken)"
|
2025-11-25 13:33:37 +01:00
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local filename
|
|
|
|
|
|
filename=$(basename "$source")
|
|
|
|
|
|
echo -e " ${DIM}${filename}${RESET}"
|
|
|
|
|
|
echo -e " Cache: ${cache_status}"
|
|
|
|
|
|
echo -e " Link: ${link_status}"
|
|
|
|
|
|
done
|
2025-11-25 13:33:37 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# MAIN WORKFLOW
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
process_models() {
|
|
|
|
|
|
local action="$1"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_section "Processing Models (${action})"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local total
|
|
|
|
|
|
total=$(get_model_count "$CONFIG_FILE")
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ "$total" == "0" ]]; then
|
|
|
|
|
|
print_warning "No models found in configuration"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
return 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local processed=0
|
2025-11-22 02:13:07 +01:00
|
|
|
|
local succeeded=0
|
|
|
|
|
|
local failed=0
|
2025-11-26 15:01:27 +01:00
|
|
|
|
local skipped=0
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
for ((i=0; i<total; i++)); do
|
|
|
|
|
|
local repo_id category description
|
|
|
|
|
|
repo_id=$(get_model_field "$CONFIG_FILE" "$i" "repo_id")
|
|
|
|
|
|
category=$(get_model_field "$CONFIG_FILE" "$i" "category")
|
|
|
|
|
|
description=$(get_model_field "$CONFIG_FILE" "$i" "description")
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Skip entries without repo_id (might be malformed YAML)
|
|
|
|
|
|
if [[ -z "$repo_id" ]]; then
|
|
|
|
|
|
continue
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Apply filters
|
|
|
|
|
|
if ! matches_filters "$repo_id" "$category"; then
|
|
|
|
|
|
skipped=$((skipped+1))
|
|
|
|
|
|
continue
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
processed=$((processed+1))
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
print_step "$processed" "$((total-skipped))" "${BOLD_CYAN}${repo_id}${RESET}"
|
|
|
|
|
|
|
|
|
|
|
|
local result=0
|
|
|
|
|
|
case "$action" in
|
|
|
|
|
|
download)
|
|
|
|
|
|
download_model "$CONFIG_FILE" "$i" "$repo_id" "$description" || result=1
|
|
|
|
|
|
;;
|
|
|
|
|
|
link)
|
|
|
|
|
|
link_model "$CONFIG_FILE" "$i" "$repo_id" || result=1
|
|
|
|
|
|
;;
|
|
|
|
|
|
verify)
|
|
|
|
|
|
verify_model "$CONFIG_FILE" "$i" "$repo_id"
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
if [[ $result -eq 0 ]]; then
|
2025-11-22 16:26:43 +01:00
|
|
|
|
succeeded=$((succeeded+1))
|
2025-11-22 02:13:07 +01:00
|
|
|
|
else
|
2025-11-22 16:26:43 +01:00
|
|
|
|
failed=$((failed+1))
|
2025-11-22 02:13:07 +01:00
|
|
|
|
fi
|
2025-11-26 15:01:27 +01:00
|
|
|
|
done
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
echo ""
|
|
|
|
|
|
if [[ $skipped -gt 0 ]]; then
|
|
|
|
|
|
print_info "Skipped ${skipped} model(s) (filtered)"
|
|
|
|
|
|
fi
|
|
|
|
|
|
print_info "Summary: ${BOLD_GREEN}${succeeded} succeeded${RESET}, ${BOLD_RED}${failed} failed${RESET}"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
show_help() {
|
|
|
|
|
|
cat << 'EOF'
|
|
|
|
|
|
HuggingFace Model Downloader - A Beautiful CLI Tool
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
Usage: artifact_huggingface_download.sh [COMMAND] [OPTIONS]
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
Commands:
|
|
|
|
|
|
download Download models to cache directory (default)
|
|
|
|
|
|
link Create symlinks from cache to output directory
|
|
|
|
|
|
verify Verify model status (cache and symlinks)
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
Options:
|
|
|
|
|
|
-c, --config FILE Configuration YAML file (required)
|
|
|
|
|
|
--cache-dir DIR Cache directory
|
|
|
|
|
|
--output-dir DIR Output/installation directory
|
|
|
|
|
|
--category CAT1,CAT2 Filter by category (comma-separated)
|
|
|
|
|
|
--repo-id ID1,ID2 Filter by repo_id (comma-separated)
|
|
|
|
|
|
--auth-token TOKEN HuggingFace token (or set HF_TOKEN env var)
|
|
|
|
|
|
-n, --dry-run Show what would be done without making changes
|
|
|
|
|
|
-h, --help Show this help message
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
Environment Variables:
|
|
|
|
|
|
HF_TOKEN HuggingFace API token
|
|
|
|
|
|
CACHE_DIR Override default cache directory
|
|
|
|
|
|
OUTPUT_DIR Override default output directory
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
YAML Configuration Format:
|
|
|
|
|
|
- repo_id: organization/model-name
|
|
|
|
|
|
description: Model description
|
|
|
|
|
|
category: image|video|llm|upscale
|
|
|
|
|
|
files:
|
|
|
|
|
|
- source: path/to/file.safetensors
|
|
|
|
|
|
dest: subdir/output_filename.safetensors
|
2025-11-25 13:33:37 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
Examples:
|
|
|
|
|
|
# Download all models from config
|
|
|
|
|
|
./artifact_huggingface_download.sh download -c models_huggingface.yaml
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Download only image models
|
|
|
|
|
|
./artifact_huggingface_download.sh download -c models_huggingface.yaml --category image
|
|
|
|
|
|
|
|
|
|
|
|
# Download specific model
|
|
|
|
|
|
./artifact_huggingface_download.sh download -c models_huggingface.yaml --repo-id black-forest-labs/FLUX.1-schnell
|
|
|
|
|
|
|
|
|
|
|
|
# Create symlinks for downloaded models
|
|
|
|
|
|
./artifact_huggingface_download.sh link -c models_huggingface.yaml
|
|
|
|
|
|
|
|
|
|
|
|
# Verify all models
|
|
|
|
|
|
./artifact_huggingface_download.sh verify -c models_huggingface.yaml
|
|
|
|
|
|
|
|
|
|
|
|
# Dry-run to preview operations
|
|
|
|
|
|
./artifact_huggingface_download.sh download -c models_huggingface.yaml --dry-run
|
|
|
|
|
|
|
|
|
|
|
|
EOF
|
|
|
|
|
|
}
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
|
|
|
|
|
main() {
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Check for yq
|
|
|
|
|
|
check_yq
|
|
|
|
|
|
|
|
|
|
|
|
# Load token from .env files
|
|
|
|
|
|
load_env_token
|
|
|
|
|
|
|
|
|
|
|
|
# Display banner
|
|
|
|
|
|
print_banner "${ROCKET} HuggingFace Model Downloader ${SPARKLES}"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Show dry-run warning
|
2025-11-25 16:46:44 +01:00
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
|
|
|
|
echo -e "${BOLD_YELLOW}${WARNING} DRY-RUN MODE - No changes will be made ${WARNING}${RESET}\n"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-22 02:13:07 +01:00
|
|
|
|
# Validate configuration
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_section "Configuration"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
|
|
|
|
|
|
if [[ -z "$CONFIG_FILE" ]]; then
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_error "Configuration file required. Use -c/--config"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
|
|
|
|
print_error "Configuration file not found: $CONFIG_FILE"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_success "Config: ${CYAN}${CONFIG_FILE}${RESET}"
|
|
|
|
|
|
print_success "Cache: ${CYAN}${CACHE_DIR}${RESET}"
|
|
|
|
|
|
print_success "Output: ${CYAN}${OUTPUT_DIR}${RESET}"
|
|
|
|
|
|
print_success "Command: ${BOLD_CYAN}${COMMAND}${RESET}"
|
|
|
|
|
|
|
|
|
|
|
|
# Show token status (not required for public repos)
|
|
|
|
|
|
if [[ -n "$HF_TOKEN" ]]; then
|
|
|
|
|
|
print_success "HF Token: ${DIM}${HF_TOKEN:0:8}...${RESET}"
|
2025-11-25 13:33:37 +01:00
|
|
|
|
else
|
2025-11-26 15:01:27 +01:00
|
|
|
|
print_info "HF Token: ${DIM}not set (public repos only)${RESET}"
|
2025-11-25 13:33:37 +01:00
|
|
|
|
fi
|
2025-11-26 15:01:27 +01:00
|
|
|
|
|
|
|
|
|
|
# Show filters if set
|
|
|
|
|
|
[[ -n "$CATEGORY_FILTER" ]] && print_info "Category filter: ${BOLD_WHITE}${CATEGORY_FILTER}${RESET}"
|
|
|
|
|
|
[[ -n "$REPO_ID_FILTER" ]] && print_info "Repo ID filter: ${BOLD_WHITE}${REPO_ID_FILTER}${RESET}"
|
|
|
|
|
|
|
|
|
|
|
|
# Process based on command
|
|
|
|
|
|
process_models "$COMMAND"
|
|
|
|
|
|
|
|
|
|
|
|
# Final message
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
print_banner "${SPARKLES} Complete ${SPARKLES}"
|
2025-11-22 02:13:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# ARGUMENT PARSING
|
2025-11-22 02:13:07 +01:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
|
|
|
case $1 in
|
|
|
|
|
|
-c|--config)
|
|
|
|
|
|
CONFIG_FILE="$2"
|
|
|
|
|
|
shift 2
|
|
|
|
|
|
;;
|
|
|
|
|
|
--cache-dir)
|
|
|
|
|
|
CACHE_DIR="$2"
|
|
|
|
|
|
shift 2
|
|
|
|
|
|
;;
|
2025-11-26 15:01:27 +01:00
|
|
|
|
--output-dir)
|
|
|
|
|
|
OUTPUT_DIR="$2"
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
shift 2
|
|
|
|
|
|
;;
|
2025-11-26 15:01:27 +01:00
|
|
|
|
--category)
|
2025-11-25 16:46:44 +01:00
|
|
|
|
CATEGORY_FILTER="$2"
|
|
|
|
|
|
shift 2
|
|
|
|
|
|
;;
|
2025-11-26 15:01:27 +01:00
|
|
|
|
--repo-id)
|
|
|
|
|
|
REPO_ID_FILTER="$2"
|
|
|
|
|
|
shift 2
|
|
|
|
|
|
;;
|
|
|
|
|
|
--auth-token)
|
|
|
|
|
|
HF_TOKEN="$2"
|
|
|
|
|
|
shift 2
|
2025-11-25 16:46:44 +01:00
|
|
|
|
;;
|
2025-11-26 15:01:27 +01:00
|
|
|
|
-n|--dry-run)
|
2025-11-25 16:46:44 +01:00
|
|
|
|
DRY_RUN=true
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
2025-11-26 15:01:27 +01:00
|
|
|
|
download|link|verify)
|
feat: add ComfyUI symlink functionality and subcommands
Adds subcommand structure (download, link, both) to the ComfyUI downloader script, allowing users to download models from HuggingFace and/or create symlinks to ComfyUI model directories. Features include:
- New subcommands: download (download only), link (symlink only), both (default)
- ComfyUI directory configuration (--comfyui-dir, default: ~/ComfyUI/models)
- Smart symlink creation to appropriate ComfyUI subdirectories (checkpoints, vae, loras, controlnet, upscale_models, etc.)
- YAML configuration extended with 'type' and 'filename' fields for precise model organization
- Automatic ComfyUI subdirectory creation
- Graceful handling of existing symlinks and files
- HF_TOKEN validation only when needed (download/both commands)
- Example configuration file (comfyui_models.example.yaml) demonstrating proper setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 02:20:46 +01:00
|
|
|
|
COMMAND="$1"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
2025-11-22 02:13:07 +01:00
|
|
|
|
-h|--help)
|
2025-11-26 15:01:27 +01:00
|
|
|
|
show_help
|
2025-11-22 02:13:07 +01:00
|
|
|
|
exit 0
|
|
|
|
|
|
;;
|
|
|
|
|
|
-*)
|
|
|
|
|
|
print_error "Unknown option: $1"
|
|
|
|
|
|
echo "Use --help for usage information"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Positional argument - treat as config file
|
|
|
|
|
|
if [[ -z "$CONFIG_FILE" ]]; then
|
|
|
|
|
|
CONFIG_FILE="$1"
|
|
|
|
|
|
fi
|
2025-11-22 02:13:07 +01:00
|
|
|
|
shift
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
done
|
|
|
|
|
|
|
2025-11-26 15:01:27 +01:00
|
|
|
|
# Run main
|
2025-11-22 02:13:07 +01:00
|
|
|
|
main
|