[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EF0R1BAEXPMDZ8RGVP53JV":3,"skill-same:01M6EF0R1BAEXPMDZ8RGVP53JV":47},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":20,"linkOnly":21,"markdownContent":22,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":27,"repositoryHtmlUrl":28,"repositoryHomepageUrl":29,"ownerHtmlUrl":30,"ownerBlogUrl":6,"ownerDescription":31,"updatedAt":32,"install":33,"resources":46},"01M6EF0R1BAEXPMDZ8RGVP53JV","file-organizer",null,"ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Ffile-organizer\u002FSKILL.md",[],[18,19],"file","file organizer","2026-11-10 10:12:30",false,"# File Organizer\n\n## Overview\n\nOrganize, rename, and categorize files based on content analysis, metadata, and patterns. Handles messy directories by sorting files into logical folder structures, applying consistent naming conventions, and detecting duplicates. Works with any file type.\n\n## Instructions\n\nWhen a user asks to organize files, determine which operation they need:\n\n### Task A: Sort files by type into folders\n\n```bash\n#!\u002Fbin\u002Fbash\n# organize_by_type.sh - Sort files into folders by extension\nSOURCE_DIR=\"${1:-.}\"\nDRY_RUN=\"${2:-false}\"\n\ndeclare -A TYPE_MAP=(\n  # Documents\n  [\"pdf\"]=\"Documents\u002FPDF\" [\"docx\"]=\"Documents\u002FWord\" [\"doc\"]=\"Documents\u002FWord\"\n  [\"xlsx\"]=\"Documents\u002FExcel\" [\"csv\"]=\"Documents\u002FCSV\" [\"txt\"]=\"Documents\u002FText\"\n  # Images\n  [\"jpg\"]=\"Images\" [\"jpeg\"]=\"Images\" [\"png\"]=\"Images\"\n  [\"gif\"]=\"Images\" [\"svg\"]=\"Images\" [\"webp\"]=\"Images\"\n  # Video\n  [\"mp4\"]=\"Video\" [\"mkv\"]=\"Video\" [\"avi\"]=\"Video\" [\"mov\"]=\"Video\"\n  # Audio\n  [\"mp3\"]=\"Audio\" [\"wav\"]=\"Audio\" [\"flac\"]=\"Audio\"\n  # Code\n  [\"py\"]=\"Code\u002FPython\" [\"js\"]=\"Code\u002FJavaScript\" [\"ts\"]=\"Code\u002FTypeScript\"\n  # Archives\n  [\"zip\"]=\"Archives\" [\"tar\"]=\"Archives\" [\"gz\"]=\"Archives\" [\"rar\"]=\"Archives\"\n)\n\nfind \"$SOURCE_DIR\" -maxdepth 1 -type f | while read -r file; do\n  ext=\"${file##*.}\"\n  ext=\"${ext,,}\"  # lowercase\n  dest=\"${TYPE_MAP[$ext]:-Other}\"\n\n  if [ \"$DRY_RUN\" = \"true\" ]; then\n    echo \"[DRY RUN] $file -> $SOURCE_DIR\u002F$dest\u002F\"\n  else\n    mkdir -p \"$SOURCE_DIR\u002F$dest\"\n    mv \"$file\" \"$SOURCE_DIR\u002F$dest\u002F\"\n    echo \"Moved: $(basename \"$file\") -> $dest\u002F\"\n  fi\ndone\n```\n\n### Task B: Smart rename based on patterns\n\n```python\nimport os\nimport re\nfrom pathlib import Path\nfrom datetime import datetime\n\ndef rename_by_pattern(directory: str, pattern: str, dry_run: bool = True):\n    \"\"\"\n    Rename files using pattern substitution.\n    Patterns: {date}, {n}, {ext}, {name}, {YYYY}, {MM}, {DD}\n    \"\"\"\n    files = sorted(Path(directory).iterdir())\n    files = [f for f in files if f.is_file()]\n\n    for i, filepath in enumerate(files, 1):\n        stat = filepath.stat()\n        mtime = datetime.fromtimestamp(stat.st_mtime)\n\n        new_name = pattern\n        new_name = new_name.replace(\"{name}\", filepath.stem)\n        new_name = new_name.replace(\"{ext}\", filepath.suffix)\n        new_name = new_name.replace(\"{n}\", str(i).zfill(3))\n        new_name = new_name.replace(\"{date}\", mtime.strftime(\"%Y-%m-%d\"))\n        new_name = new_name.replace(\"{YYYY}\", str(mtime.year))\n        new_name = new_name.replace(\"{MM}\", str(mtime.month).zfill(2))\n        new_name = new_name.replace(\"{DD}\", str(mtime.day).zfill(2))\n\n        new_path = filepath.parent \u002F new_name\n        if dry_run:\n            print(f\"  {filepath.name} -> {new_name}\")\n        else:\n            filepath.rename(new_path)\n            print(f\"  Renamed: {filepath.name} -> {new_name}\")\n\n# Example: rename photos to date-based names\nrename_by_pattern(\".\u002Fphotos\", \"{date}_photo_{n}{ext}\", dry_run=True)\n```\n\n### Task C: Content-based organization using file metadata\n\n```python\nimport os\nimport shutil\nfrom pathlib import Path\nfrom datetime import datetime\n\ndef organize_by_date(directory: str, date_format: str = \"%Y\u002F%Y-%m\"):\n    \"\"\"Sort files into year\u002Fyear-month folders based on modification date.\"\"\"\n    for filepath in Path(directory).iterdir():\n        if not filepath.is_file() or filepath.name.startswith('.'):\n            continue\n        mtime = datetime.fromtimestamp(filepath.stat().st_mtime)\n        dest_dir = Path(directory) \u002F mtime.strftime(date_format)\n        dest_dir.mkdir(parents=True, exist_ok=True)\n        shutil.move(str(filepath), str(dest_dir \u002F filepath.name))\n        print(f\"  {filepath.name} -> {dest_dir}\u002F\")\n\ndef organize_by_size(directory: str):\n    \"\"\"Sort files into small\u002Fmedium\u002Flarge folders.\"\"\"\n    size_buckets = [\n        (1_000_000, \"small_under_1MB\"),\n        (100_000_000, \"medium_1MB_to_100MB\"),\n        (float('inf'), \"large_over_100MB\")\n    ]\n    for filepath in Path(directory).iterdir():\n        if not filepath.is_file():\n            continue\n        size = filepath.stat().st_size\n        for threshold, folder in size_buckets:\n            if size \u003C threshold:\n                dest = Path(directory) \u002F folder\n                dest.mkdir(exist_ok=True)\n                shutil.move(str(filepath), str(dest \u002F filepath.name))\n                break\n```\n\n### Task D: Find and handle duplicates\n\n```python\nimport hashlib\nfrom pathlib import Path\nfrom collections import defaultdict\n\ndef find_duplicates(directory: str, recursive: bool = True) -> dict[str, list[Path]]:\n    \"\"\"Find duplicate files by content hash.\"\"\"\n    hash_map = defaultdict(list)\n    glob_pattern = \"**\u002F*\" if recursive else \"*\"\n\n    for filepath in Path(directory).glob(glob_pattern):\n        if not filepath.is_file():\n            continue\n        file_hash = hashlib.md5(filepath.read_bytes()).hexdigest()\n        hash_map[file_hash].append(filepath)\n\n    # Return only groups with duplicates\n    return {h: paths for h, paths in hash_map.items() if len(paths) > 1}\n\ndef report_duplicates(directory: str):\n    dupes = find_duplicates(directory)\n    total_wasted = 0\n    for file_hash, paths in dupes.items():\n        size = paths[0].stat().st_size\n        wasted = size * (len(paths) - 1)\n        total_wasted += wasted\n        print(f\"\\nDuplicate group ({len(paths)} copies, {size:,} bytes each):\")\n        for p in paths:\n            print(f\"  {p}\")\n\n    print(f\"\\nTotal duplicates: {sum(len(p)-1 for p in dupes.values())} files\")\n    print(f\"Wasted space: {total_wasted \u002F 1_000_000:.1f} MB\")\n\nreport_duplicates(\".\u002Fdocuments\")\n```\n\n## Examples\n\n### Example 1: Clean up a messy Downloads folder\n\n**User request:** \"Organize my Downloads folder, it has 500+ mixed files\"\n\n```bash\n# First, preview what will happen (dry run)\nbash organize_by_type.sh ~\u002FDownloads true\n\n# If the preview looks good, run for real\nbash organize_by_type.sh ~\u002FDownloads false\n```\n\nResult: Files sorted into `Documents\u002F`, `Images\u002F`, `Video\u002F`, `Audio\u002F`, `Code\u002F`, `Archives\u002F`, and `Other\u002F`.\n\n### Example 2: Rename photos with date-based names\n\n**User request:** \"Rename all photos to YYYY-MM-DD format based on when they were taken\"\n\n```python\nrename_by_pattern(\n    \".\u002Fvacation_photos\",\n    \"{date}_IMG_{n}.jpg\",\n    dry_run=False\n)\n# Result: IMG_4521.jpg -> 2025-06-15_IMG_001.jpg\n```\n\n### Example 3: Find and report duplicate files\n\n**User request:** \"Find all duplicate files in my project and show how much space they waste\"\n\n```python\nreport_duplicates(\"\u002Fhome\u002Fuser\u002Fproject\")\n# Output:\n# Duplicate group (3 copies, 245,760 bytes each):\n#   \u002Fhome\u002Fuser\u002Fproject\u002Fassets\u002Flogo.png\n#   \u002Fhome\u002Fuser\u002Fproject\u002Fbackup\u002Flogo.png\n#   \u002Fhome\u002Fuser\u002Fproject\u002Fold\u002Flogo.png\n#\n# Total duplicates: 47 files\n# Wasted space: 123.4 MB\n```\n\n## Guidelines\n\n- Always run with a dry-run or preview mode first before moving or renaming files.\n- Never delete files automatically. Move duplicates to a `_duplicates\u002F` staging folder for user review.\n- Preserve original file timestamps when moving files with `shutil.move` or `mv -p`.\n- Skip hidden files and system files (starting with `.`) by default.\n- Handle filename collisions by appending a counter: `file.txt`, `file_1.txt`, `file_2.txt`.\n- For large directories (10,000+ files), process in batches and show progress.\n- Log all operations to a file so they can be reviewed or undone.\n- Use content hashing (MD5 or SHA256) for duplicate detection, not just filename matching.\n",{},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002FTerminalSkills\u002Fskills\u002Ffile-organizer",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":7,"skillName":5,"commands":34,"prompt":44,"zipAvailable":45},[35,38,41],{"tool":36,"command":37},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill file-organizer",{"tool":39,"command":40},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill file-organizer",{"tool":42,"command":43},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill file-organizer","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Ffile-organizer\u002FSKILL.md",true,[],[48,62,72,81,87,94],{"skillNo":49,"name":50,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":51,"categories":52,"keywords":58,"publishedAt":20},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[53],{"categoryNo":54,"categoryName":55,"taxonomyType":56,"taxonomyTypeDesc":57},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[59,60,61],"model","model hierarchy","model hierarchy skill",{"skillNo":63,"name":64,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":68,"publishedAt":20},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[67],{"categoryNo":54,"categoryName":55,"taxonomyType":56,"taxonomyTypeDesc":57},[69,70,71],"MCP","zoom","zoom mcp",{"skillNo":73,"name":74,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":75,"categories":76,"keywords":77,"publishedAt":20},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[78,79,80,70],"sdk","zoom apps sdk","apps",{"skillNo":82,"name":83,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":86,"publishedAt":20},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[83],{"skillNo":88,"name":89,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":93,"publishedAt":20},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[92],{"categoryNo":54,"categoryName":55,"taxonomyType":56,"taxonomyTypeDesc":57},[89],{"skillNo":95,"name":96,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":99,"publishedAt":20},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[96]]