lionad-morotar/local-tools/archive-behance

Claude Code and agent skill by lionad-morotar/local-tools

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Archive Behance projects to Eagle DAM (Digital Asset Management) library. Use when user wants to archive or save a Behance project URL to their Eagle collection with proper metadata. Triggers include requests like '归档 https://www.behance.net/gallery/...', '保存 Behance 项目', 'archive behance project', or any request to download or save Behance gallery content to local Eagle library.

Install

npx vskill@latest install lionad-morotar/local-tools/archive-behance

SKILL.md

Archive Behance

Archive Behance projects to Eagle DAM library with proper folder structure and metadata.

Workflow

When user requests to archive a Behance URL:

  1. Extract project info from the Behance page:
  • Project title
  • Creative field/category (e.g., "Illustration", "Graphic Design")
  • All project images (from mir-s3-cdn domain)
  • Tags
  1. Determine target folder in Eagle library:
  • Base path: Collections > Behance
  • Subfolder based on creative field:
  • "Illustration" → 插画
  • "Graphic Design" → 平面设计
  • "Photography" → 摄影
  • "UI/UX" → UI/UX
  • "Motion Graphics" → 动效
  • "Typography" → 字体设计
  • Others → ask user or use 未分类
  1. Create project folder with sanitized name (slug from URL or project title)
  1. Download images and create Eagle metadata:
  • Use original image URL from mir-s3-cdn-cf.behance.net
  • Name: use image alt text or generate sequential name
  • URL: image source URL (permanent link)
  • Tags: optional, can be empty
  1. Provide summary to user with download statistics

Browser Access

Use Playwright MCP (mcp__plugin_playwright_playwright__browser_navigate) to access Behance pages.

Never write Python/shell scripts that call Playwright directly.

Extracting Project Data

Use JavaScript evaluation to extract:

javascript
// Get project info and images
() => {
const images = [];
document.querySelectorAll('img').forEach((img, i) => {
if (img.src && img.src.includes('mir-s3-cdn')) {
images.push({
src: img.src,
alt: img.alt || '',
width: img.width,
height: img.height
});
}
});
// Filter to main project images only (exclude thumbnails and avatars)
const mainImages = images.filter(img =>
img.src.includes('project_modules') &&
!img.src.includes('/projects/404/')
);
return {
title: document.querySelector('h1')?.textContent?.trim() || '',
creativeField: document.querySelector('a[href*="field="]')?.textContent?.trim() || '',
tags: Array.from(document.querySelectorAll('a[href*="tracking_source=project_tag"]'))
.map(t => t.textContent.trim()),
images: mainImages
};
}

Finding Target Folder in metadata.json

Important: metadata.json can be very large (100k+ tokens). Never read the entire file into memory.

Method 1: Using grep (Recommended)

Use grep to extract just the folder ID without loading the entire file:

python
import subprocess
import json
from pathlib import Path
def find_folder_id_by_name(library_root: Path, folder_name: str) -> str:
"""
Find folder ID by name using grep (memory efficient).
Returns folder ID or None if not found.
"""
metadata_path = library_root / "metadata.json"
# Use grep to find the line with the folder name
result = subprocess.run(
['grep', '-B', '5', f'"name": "{folder_name}"', str(metadata_path)],
capture_output=True, text=True
)
if result.returncode != 0:
return None
# Parse the output to find ID
for line in result.stdout.split('\n'):
if '"id":' in line:
# Extract ID from "id": "ABC123"
import re
match = re.search(r'"id":\s*"([^"]+)"', line)
if match:
return match.group(1)
return None
# Usage: Find "图形设计" folder ID
folder_id = find_folder_id_by_name(Path("."), "图形设计")
Method 2: Using ijson (Streaming Parser)

For complex searches through nested structures, use ijson to stream-parse:

python
import ijson
from pathlib import Path
def find_behance_folder(library_root: Path, creative_field: str) -> str:
"""
Find Behance subfolder ID using streaming JSON parser.
Memory efficient for large metadata files.
"""
metadata_path = library_root / "metadata.json"
field_map = {
"Illustration": "插图",
"Graphic Design": "图形设计",
"Photography": "摄影",
"UI/UX": "UI/UX",
"Motion Graphics": "动画",
"Typography": "字体设计",
"Branding": "图形设计",
"3D Art": "3D Art",
"Architecture": "建筑",
"Fashion": "时尚",
"Advertising": "广告",
"Fine Arts": "美术",
"Crafts": "手工艺",
"Game Design": "游戏设计",
}
target_name = field_map.get(creative_field, "未分类")
with open(metadata_path, 'rb') as f:
# Stream through folders
for folder in ijson.items(f, 'folders.item'):
if folder.get('name') == 'Collections':
for child in folder.get('children', []):
if child.get('name') == 'Behance':
for subfolder in child.get('children', []):
if subfolder.get('name') == target_name:
return subfolder['id']
return None
Method 3: Cached Folder IDs

For repeated operations, cache the folder IDs:

python
# Cache of known Behance folder IDs (update as needed)
BEHANCE_FOLDER_IDS = {
"插图": "7UAPMLRGTWT",
"图形设计": "UWFE6X4QRC4",
"摄影": "36QLX1XSJCC",
"UI/UX": "LKC0V82UMSW",
"动画": "25BUAQGOJFH",
"3D Art": "6GIONKGOYTW",
"建筑": "CQPDELSDAAY",
"产品设计": "6FODRRZQTFO",
"时尚": "SWHR57VFNM0",
"广告": "JC3ZLIHEUSG",
"美术": "KP2UWOJ4WDN",
"手工艺": "PMQ8B3ODHKY",
"游戏设计": "0JAUXK03C29",
"声音": "ZS4GICO0BY8",
}
def get_behance_folder_id(creative_field: str) -> str:
"""Get folder ID from cache or use fallback."""
field_map = {
"Illustration": "插图",
"Graphic Design": "图形设计",
"Photography": "摄影",
"UI/UX": "UI/UX",
"Motion Graphics": "动画",
"Typography": "字体设计",
"Branding": "图形设计",
"3D Art": "3D Art",
"Architecture": "建筑",
"Fashion": "时尚",
"Advertising": "广告",
"Fine Arts": "美术",
"Crafts": "手工艺",
"Game Design": "游戏设计",
"Label Design": "图形设计",
}
target_name = field_map.get(creative_field)
if target_name:
return BEHANCE_FOLDER_IDS.get(target_name)
return None
Field to Folder Mapping
Behance Creative FieldEagle Folder NameCached ID
Illustration插图7UAPMLRGTWT
Graphic Design图形设计UWFE6X4QRC4
Branding图形设计UWFE6X4QRC4
Label Design图形设计UWFE6X4QRC4
Photography摄影36QLX1XSJCC
UI/UXUI/UXLKC0V82UMSW
Motion Graphics动画25BUAQGOJFH
Typography字体设计(varies)
3D Art3D Art6GIONKGOYTW
Architecture建筑CQPDELSDAAY
Fashion时尚SWHR57VFNM0
Advertising广告JC3ZLIHEUSG
Fine Arts美术KP2UWOJ4WDN
Crafts手工艺PMQ8B3ODHKY
Game Design游戏设计0JAUXK03C29

Downloading Images

Use Python requests to download images with proper headers:

python
import requests
from pathlib import Path
import time
def download_image(url: str, dest_path: Path, max_retries: int = 3) -> int:
"""
Download image from Behance CDN.
Returns file size in bytes.
"""
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"Referer": "https://www.behance.net/"
}
for attempt in range(max_retries):
try:
response = requests.get(url, headers=headers, timeout=60)
response.raise_for_status()
dest_path.write_bytes(response.content)
return len(response.content)
except Exception as e:
if attempt == max_retries - 1:
raise
time.sleep(1) # Wait before retry
Handling SSL Errors

If you encounter SSLEOFError during batch downloads:

  • Implement retry logic with exponential backoff
  • Reduce concurrent connections
  • Use smaller batch sizes

Image URL Patterns

Behance images follow these patterns:

  • Source: https://mir-s3-cdn-cf.behance.net/project_modules/{size}/{hash}.{ext}
  • Size variants: max_632, 1400, 1400_webp, original
  • For archiving: use the largest available (1400 or original)

To get original size, replace size in URL:

/max_632_webp/ → /original/
/1400_webp/ → /original/

Folder Mapping

Behance Creative FieldEagle Folder NameFolder ID Example
Illustration插图7UAPMLRGTWT
Graphic Design图形设计UWFE6X4QRC4
Photography摄影36QLX1XSJCC
UI/UXUI/UXLKC0V82UMSW
Motion Graphics动画25BUAQGOJFH
Typography字体设计(varies)
3D Art3D Art6GIONKGOYTW
Architecture建筑CQPDELSDAAY
Fashion时尚SWHR57VFNM0
Advertising广告JC3ZLIHEUSG
Fine Arts美术KP2UWOJ4WDN
Crafts手工艺PMQ8B3ODHKY
Game Design游戏设计0JAUXK03C29
(unknown)未分类ask user

Creating Eagle Metadata

Eagle stores metadata in images/{ID}.info/metadata.json:

python
import json
import random
import string
from pathlib import Path
from datetime import datetime
from PIL import Image
def generate_eagle_id() -> str:
"""
Generate correct Eagle ID format.
- Asset ID: K + 12 chars = 13 chars total
- Folder ID: 11-13 chars, can start with any character
"""
chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
return 'K' + ''.join(random.choices(chars, k=12))
def create_thumbnail(img_path: Path, thumb_path: Path, size=(240, 240)):
"""Create thumbnail for Eagle display."""
with Image.open(img_path) as img:
if img.mode in ('RGBA', 'P'):
img = img.convert('RGB')
img.thumbnail(size, Image.Resampling.LANCZOS)
background = Image.new('RGB', size, (255, 255, 255))
offset = ((size[0] - img.width) // 2, (size[1] - img.height) // 2)
background.paste(img, offset)
background.save(thumb_path, 'PNG')
def get_exif_orientation(img) -> int:
"""Get EXIF orientation, default to 1 (normal)."""
try:
exif = img._getexif()
if exif and 274 in exif:
return exif[274]
except:
pass
return 1
def create_eagle_asset(
library_root: Path,
image_url: str,
name: str,
folder_id: str,
tags: list = None
) -> dict:
"""
Create a complete Eagle asset with proper metadata.
CRITICAL: Must include all required fields for Eagle to recognize.
"""
# 1. Generate correct 13-char ID
asset_id = generate_eagle_id()
asset_dir = library_root / "images" / f"{asset_id}.info"
asset_dir.mkdir(parents=True, exist_ok=True)
# 2. Download image
ext = image_url.split('.')[-1].split('?')[0]
if ext not in ['jpg', 'jpeg', 'png', 'webp', 'gif']:
ext = 'jpg'
# CRITICAL: Filename must match metadata "name" field!
img_path = asset_dir / f"{name}.{ext}"
download_image(image_url, img_path)
# 3. Generate thumbnail (REQUIRED!)
# Thumbnail name must match: {name}_thumbnail.png
thumb_path = asset_dir / f"{name}_thumbnail.png"
create_thumbnail(img_path, thumb_path)
# 4. Get image info
with Image.open(img_path) as img:
width, height = img.size
orientation = get_exif_orientation(img)
stat = img_path.stat()
now_ms = int(datetime.now().timestamp() * 1000)

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
7
Repository forks
1
7-day trend score
10

Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 28 Apr 2026, 6 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/lionad-morotar/local-tools/archive-behance/badge)](https://verified-skill.com/skills/lionad-morotar/local-tools/archive-behance)

Something wrong with this skill or its page? Tell us.